<!doctype html>
<html lang="zh-cn">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, user-scalable=no">
    <meta name="renderer" content="webkit">
    <meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'>
    <title>贪吃蛇-前端路上</title>
    <meta content="贪吃蛇,前端技术学习" name="Keywords">
    <meta content="贪吃蛇是一款有趣的益智游戏，在游戏中每得10分将进入下一关，无限关卡等你挑战" name="Description">
    <meta name="format-detection" content="telephone=no">
    <link rel="stylesheet" type="text/css" href="/asset/ui.css">
    <script>
        var _hmt = _hmt || [];
        (function() {
          var hm = document.createElement("script");
          hm.src = "https://hm.baidu.com/hm.js?f10103677155b485824f29def715eb5d";
          var s = document.getElementsByTagName("script")[0]; 
          s.parentNode.insertBefore(hm, s);
        })();
    </script>
</head>

<body>
<h1 class="hide">贪吃蛇</h1>
    <a href="//refined-x.com" title="前端路上" style="position: absolute;right: 0;top:0;padding:.5em;">前端路上</a>
    <style>
    #snake-layer {
        margin: 40px auto;
    }
    .snakeHead{background:#fc0;}
    .line {
        position: absolute;
    }
    
    .lineH {
        border-bottom: 1px solid #ccc;
        width: 100%;
    }
    
    .lineS {
        border-right: 1px solid #ccc;
        height: 100%;
    }
    
    .noborder .line {
        border: 0;
    }
    </style>
    <script src="/asset/sea.js" id="seajsnode"></script>
    <script type="text/javascript" src="//static-zt.oss-cn-qingdao.aliyuncs.com/modules/manifest.js"></script>
    <script>
    seajs.config({
        base: "//static-zt.oss-cn-qingdao.aliyuncs.com/modules",
        alias: {
            "audio": "audio/audio",
            "copy": "copy/ZeroClipboard",
            "flv": "flv/flv",
            "hook": "hook/hook",
            "jquery": "jquery/1/jquery.js",
            "validform": "validform/validform",
            "My97DatePicker": "My97DatePicker/WdatePicker",
            "raty": "raty/raty",
            "upload": "upload/upload",
            "makethumb": "upload/makethumb",
            "localResizeIMG": "upload/localResizeIMG",
            "video": "video/video",
            // localstorage缓存
            "seajs-localcache": "seajs/seajs-localcache",
            // debug
            "seajs-debug": "seajs/seajs-debug"
        }
    });
    </script>
    <script>
    /**
     * index
     */
    define('scripts', function(require) {
        var $ = require('jquery');
        var box = require('box');

        var length = 20, //画布边长
            cellLength = 16, //单位长度px
            enemyNum = length * 0.5, //食物数量
            snakeLength = 3, //蛇初始长度
            mapLine = true, //显示辅助线
            direct = '+x', //初始方向
            speed = 600; //初始速度，数值越小越快

        var myLevel = 1;
        var myScore = 0;    //得分
        var layer = $('<div id="snake-layer"/ style="position: relative;border: 1px solid #ccc">');
        var snake = '<div class="snake bg-success" />';
        var random = function() {
            return Math.floor(Math.random() * length);
        };
        var snakes = [];
        var runner;
        var snakePlace = {}; //蛇头位置
        var drawMap = function(mapLine) {
            layer.css({
                width: length * cellLength,
                height: length * cellLength
            });
            $('body').append(layer);
        };
        var drawLine = function() {
            var lineH = '<div class="line lineH" />';
            var lineS = '<div class="line lineS" />';
            for (var i = 0; i < length - 1; i++) {
                layer.append($(lineH).css({
                    top: i * cellLength,
                    height: cellLength
                }).add($(lineS).css({
                    left: i * cellLength,
                    width: cellLength
                })));
            }
        };
        var addPoint = function(dom, x, y, cb) {
            dom.css({
                width: cellLength,
                height: cellLength,
                position: 'absolute',
                left: x * cellLength,
                top: y * cellLength
            });
            dom.x = x;
            dom.y = y;
            layer.append(dom);
            if (typeof(cb) === 'function') {
                cb(dom);
            }
        };
        var checkPointInSnake = function(point, correct) {
            var result = false;
            var checkArray = snakes.slice(0);
            for (var i = 0; i < checkArray.length; i++) {
                if (point.x === checkArray[i].x && point.y === checkArray[i].y) {
                    if (correct) {
                        point = {
                            x: random(),
                            y: random()
                        };
                        checkPointInSnake(point);
                    } else {
                        result = true;
                    }
                    break;
                }
            }
            if (correct) {
                return point;
            } 
            return result;
        };
        //创建食物
        var foods = [];
        var addFood = function(enemyNum) {
            for (var i = 0; i < enemyNum; i++) {
                var ememy_x = random();
                var ememy_y = random();
                var food = $('<div class="bg-danger" />');
                var point = checkPointInSnake({
                    x: ememy_x,
                    y: ememy_y
                }, true);
                point.dom = food;
                foods.push(point);
                addPoint(food, point.x, point.y);
            }
        };
        //游戏得分
        var getScore = function(){
            $('#myScore').text(++myScore);
            if (myScore % 10 === 0) {
                $('#myLevel').text(++myLevel);
                speed = Math.round(speed * 0.8);
            }
        };
        //运动
        var run = function() {
            switch (direct) {
                case "+x":
                    snakePlace.x = snakePlace.x + 1;
                    break;
                case "+y":
                    snakePlace.y = snakePlace.y - 1;
                    break;
                case "-x":
                    snakePlace.x = snakePlace.x - 1;
                    break;
                case "-y":
                    snakePlace.y = snakePlace.y + 1;
                    break;
                default:
            }
            //边界检测
            if (snakePlace.x >= length || snakePlace.x < 0 || snakePlace.y >= length || snakePlace.y < 0) {
                clearInterval(runner);
                if(window.localStorage){
                    var lastScore = parseInt(localStorage.getItem('snake-score'));
                    if(myScore > lastScore){
                        require.async('notice', function(Notice){
                           Notice({
                            title: '打破纪录！',
                            desc: '恭喜你，创造新的记录：' + myScore + '！'
                           });
                        });
                        localStorage.setItem('snake-score', myScore);
                    }
                }
                return box.alert('游戏结束！');
            }
            //自身检测
            if (checkPointInSnake(snakePlace)) {
                clearInterval(runner);
                return box.alert('游戏结束！');
            }
            $('.snakeHead').removeClass('snakeHead');
            //食物检测
            var hasFood;
            for (var i = 0; i < foods.length; i++) {
                if (snakePlace.x === foods[i].x && snakePlace.y === foods[i].y) {
                    addPoint($(snake).addClass('snakeHead'), snakePlace.x, snakePlace.y, function(dom) {
                        snakes.push(dom);
                    });
                    hasFood = true;
                    foods[i].dom.remove();
                    foods.splice(i, 1);
                    break;
                }
            }
            if (hasFood) {
                addFood(1);
                getScore();
                clearInterval(runner);
                runner = setInterval(run, speed);
            } else {
                var footer = snakes.shift();
                footer.css({
                    top: snakePlace.y * cellLength,
                    left: snakePlace.x * cellLength
                }).addClass('snakeHead');
                footer.x = snakePlace.x;
                footer.y = snakePlace.y;
                snakes.push(footer);
            }
        };
        //画地图
        drawMap(mapLine);
        if (mapLine) {
            drawLine();
        }
        //画蛇
        for (var i = 0; i < snakeLength; i++) {
            var _x = Math.floor(length / 2);
            var _y = _x;
            switch (direct) {
                case "+x":
                    _x += i;
                    break;
                case "+y":
                    _y -= i;
                    break;
                case "-x":
                    _x -= i;
                    break;
                case "-y":
                    _y += i;
                    break;
                default:
            }
            addPoint($(snake), _x, _y, function(dom) {
                //蛇头
                if (i === snakeLength - 1) {
                    snakePlace = {
                        x: _x,
                        y: _y
                    };
                    dom.addClass('snakeHead');
                }
                snakes.push(dom);
            });
        }
        //画食物
        addFood(enemyNum);
        //控制
        document.onkeydown = function(e) {
            switch (e.keyCode) {
                case 38:
                    //up
                    direct = '+y';
                    break;
                case 40:
                    //down
                    direct = '-y';
                    break;
                case 37:
                    //left
                    direct = '-x';
                    break;
                case 39:
                    //right
                    direct = '+x';
                    break;
                default:
            }
        };
        $('body')
        .append('<div class="tc"><div class="h1">关卡：<span id="myLevel">'+ myLevel +'</span> 得分：<span id="myScore">'+ myScore +'</span></div><button class="btn btn-success" id="snakeStart">开始</button> <button class="btn btn-warning" id="snakePause">暂停</button> <button class="btn btn-info" id="snakeRestart">重新开始</button> <button class="btn btn-default" id="toggleLine">切换辅助线</button><p class="m">点击开始，使用上、下、左、右箭头操作</p></div>')
            .on('click', '.btn', function() {
                var btnid = $(this).attr('id');
                switch(btnid){
                    case 'snakeStart':
                        runner = setInterval(run, speed);
                    break;
                    case 'snakePause':
                        clearInterval(runner);
                    break;
                    case 'toggleLine':
                        layer.toggleClass('noborder');
                    break;
                    case 'snakeRestart':
                        window.location.reload();
                    break;
                    default:
                }
            });
    });
    seajs.use('scripts');
    </script>
</body>

</html>
